﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using vJine.Core;

namespace vJine.Lua.GUI.BLL {
    public class ConfigManager {
        Dictionary<string, string> Configs = new Dictionary<string, string>();

        public NodeConfig config { get; private set; }
        public string config_file { get; private set; }

        const string default_config_file = "../TC/default.config";

        public void set(LuaContext context, NodeConfig nConfig, string config_file = default_config_file) {
            this.Configs.Clear();

            this.config = nConfig;
            this.config_file = config_file;

            //Load
            if (File.Exists(config_file)) {
                string[] key_values = File.ReadAllLines(config_file);
                for (int i = 0, len = key_values.Length; i < len; i++) {
                    string key_value_i = key_values[i];
                    if (string.IsNullOrEmpty(key_value_i)) {
                        continue;
                    }
                    int key_index = key_value_i.IndexOf('=');
                    if (key_index < 1) {
                        continue;
                    }

                    this.Configs.Add(
                        key_value_i.Substring(0, key_index)
                        , key_value_i.Substring(key_index + 1));
                }
            }

            nConfig.on_save = (LuaContext ctx, NodeConfig ctxConfig) => {
                this.save(ctx, ctxConfig);
            };
            this.hook_on_save(nConfig);
        }

        void hook_on_save(NodeConfig nConfig) {
            foreach (NodeConfig nConfig_i in nConfig) {
                nConfig_i.on_save = nConfig.on_save;
                this.hook_on_save(nConfig_i);
            }

            if (nConfig.configs != null) {
                foreach (NodeConfig config_i in nConfig.configs) {
                    config_i.on_save = nConfig.on_save;
                }
            }
        }

        public void save(LuaContext context, NodeConfig nConfig) {
            if (!nConfig.s) {
                return;
            }

            string config_key = 
                string.IsNullOrEmpty(nConfig.key_config) ? nConfig.uri : nConfig.key_config;

            List<object> objs = nConfig.value as List<object>;
            if (objs == null || objs.Count == 0) { //单值及单选参数
                string v = nConfig.value == null ? "" : nConfig.value.ToString();
                if (nConfig.value != null && nConfig.value.GetType() == typeof(bool)) {
                    v = v.ToLower();
                }
                if (!string.IsNullOrEmpty(v) && nConfig.value.GetType() == typeof(string)) {
                    v = "\"" + v + "\"";
                }

                this.save(context, config_key, v);
            } else { //多选参数
                string v = "";
                for (int i = 0, len_max = objs.Count - 1; i <= len_max; i++) {
                    object obj_i = objs[i];
                    if (obj_i.GetType() == typeof(string)) {
                        v += "\"" + obj_i.ToString() + "\"";
                    } else {
                        v += obj_i.ToString();
                    }
                    if (i < len_max) {
                        v += ",";
                    }
                }

                this.save(context, config_key, v);
            }
        }

        object parse(string v) {
            double numberValue = 0;
            if (v == "true") {
                return true;
            } else if (v == "false") {
                return false;
            } else if(v.StartsWith("\"") && v.EndsWith("\"")) {
                return v.Substring(1, v.Length - 2);
            } else if (double.TryParse(v, out numberValue)) {
                return numberValue;
            } else {
                return v;
            }
        }

        void save(LuaContext context, string key, string value) {
            string temp_config_file = config_file;
            int key_sep = key.IndexOf("@");
            if (key_sep > 0) {
                if (temp_config_file == default_config_file) {
                    context.exec("on_warn", "<保存配置失败>,请指定配置文件后重试");
                    return;
                }
            } else {
                temp_config_file = default_config_file;
            }
            if (string.IsNullOrEmpty(value)) {
                value = "";
            }
            if (this.Configs.ContainsKey(key)) {
                this.Configs[key] = value;
            } else {
                this.Configs.Add(key, value);
            }

            StringBuilder sbConfigs = new StringBuilder();
            foreach (KeyValuePair<string, string> config in this.Configs) {
                if (!string.IsNullOrEmpty(config.Value)) {
                    sbConfigs.AppendFormat("{0}={1}\r\n", config.Key, config.Value);
                } else {
                    sbConfigs.AppendFormat("{0}=\r\n", config.Key);
                }
            }

            string config_dir = Path.GetDirectoryName(config_file);
            if (!Directory.Exists(config_dir)) {
                Directory.CreateDirectory(config_dir);
            }
            File.WriteAllText(temp_config_file, sbConfigs.ToString());

            if (key_sep > 0) {
                key = key.Substring(0, key_sep);
            }
            context.exec("on_log",
                            string.Format("<保存配置成功>,{0}={1}", key, value));
        }

        public void setConfig(NodeConfig nConfig, bool just_key_config = false) {

            foreach (KeyValuePair<string, string> kv in this.Configs) {
                NodeConfig config_i = nConfig.get(kv.Key);
                if (config_i == null || !config_i.s) {
                    continue;
                }
                if (just_key_config && config_i.key_config != kv.Key) {
                    continue;
                }

                string stringValue = kv.Value;

                bool trig_flag = config_i.trig_on_changed;
                try {
                    config_i.trig_on_changed = false;
                    List<ListItem> list = config_i.list;
                    if (list != null && list.Count > 0) {
                        if (config_i.multi) {
                            for (int i = 0, len = list.Count; i < len; i++) {
                                list[i].Checked = false;
                            }

                            string[] V = stringValue.Split(',');
                            for (int i = 0, len_i = V.Length; i < len_i; i++) {
                                object v_i =  this.parse(V[i]);

                                for (int j = 0, len_j = list.Count; j < len_j; j++) {
                                    ListItem list_i = list[j];
                                    if (Object.Equals(list_i.Value, v_i)) {
                                        list_i.Checked = true;
                                    } else if(list_i.Checked) {
                                        continue;
                                    }
                                }
                            }
                        } else {
                            object objV = this.parse(stringValue);
                            for (int i = 0, len = list.Count; i < len; i++) {
                                ListItem list_i = list[i];
                                if (Object.Equals(list_i.Value, objV)) {
                                    list_i.Checked = true;
                                    config_i.value = objV;
                                } else {
                                    list_i.Checked = false;
                                }
                            }
                        }
                    } else {
                        config_i.value = this.parse(stringValue);
                    }
                } finally {
                    config_i.trig_on_changed = trig_flag;
                }
            }
        }
        /// <summary>
        /// 加载配置文件，绑定保存方法
        /// </summary>
        /// <param name="config_file">配置文件名称</param>
        /// <param name="nConfig"></param>
        /// <returns></returns>
        public static ConfigManager load_config(string config_file, NodeConfig nConfig) {
            //TODO: 需要在主context加载完成后调用，否则会被覆盖
            ConfigManager cm = new ConfigManager() {
                config_file = config_file
            };
            cm.set(null, nConfig, config_file);
            cm.setConfig(nConfig);
            return cm;
        }
    }
}
